
__author__="Peter"
__date__ ="$Apr 24, 2011 7:14:12 AM$"

## Core class library for use with Project Awesome

## Important imports!
from math import *
from graphics import *
from applied_math import *
from core.place_charges_OOP import *

## Important constants!

## This is the Particle's constant charge:
PARTICLE_CHARGE = 1

## This is the standard menu width in the display window:
MENU_WIDTH = 30

## This is the period of each step of the program, in seconds per update:
SEC_PER_UPDATE = (24)**(-1)

## This is the universal mass of PArticle objects, in kilograms
PARTICLE_MASS = 1



class Charge:
    """Responsible for representing a stationary charged particle"""

    def __init__(self, pointPosition, charge):
        """Creates a Charge object from a Point pointPosition representing its position
        and an integer charge representing its charge"""
        self.x = pointPosition.getX()
        self.y = pointPosition.getY()
        self.charge = charge
        self.circle = None

    def getX(self):
        """Return this Charge's x position"""
        return self.x

    def getY(self):
        """Return this Charge's y position"""
        return self.y

    def getPosition(self):
        """Returns the Charge's position as a Point object"""
        return Point(self.x, self.y)

    def getCharge(self):
        """Return this Charge's magnitude"""
        return self.charge
    
    def setCharge(self, charge):
        self.charge = charge

    def setPosition(self, pointPos):
        self.x = pointPos.getX()
        self.y = pointPos.getY()
    
    def undraw(self):
        self.circle.undraw()

    def draw(self, window):
        self.circle = Circle(Point(self.x, self.y), 10)
        if self.charge == 1:
            self.circle.setFill('blue')
        else:
            self.circle.setFill('red')
        self.circle.draw(window)




class Particle:
    """Responsible for representing a positively charged moving particle"""

    def __init__(self, pointPosition):
        """Creates a Particle object from a Point pointPosition representing its position"""
        self.x = pointPosition.getX()
        self.y = pointPosition.getY()
        self.charge = PARTICLE_CHARGE
        self.mass = PARTICLE_MASS
        self.vx = 0
        self.vy = 0
        self.circle = Circle(pointPosition,10)

    def getX(self):
        """Return this Particle's x position"""
        return self.x

    def getY(self):
        """Return this Particle's y position"""
        return self.y

    def getPosition(self):
        """Returns the Particle's position as a Point object"""
        return Point(self.x,self.y)

    def getCharge(self):
        """Returns the Particle's charge magnitude"""
        return self.charge

    def getXVelocity(self):
        """Return this Particle's x velocity"""
        return self.vx

    def getYVelocity(self):
        """Return this Particle's y velocity"""
        return self.vy

    def getVelocity(self):
        """Return this Particle's velocity as a two-element list"""
        return [self.vx,self.vy]

    def getMass(self):
        """Return this Particle's mass"""
        return self.mass

    def draw(self, window):
        self.circle.setFill('black')
        self.circle.draw(window)

    def hitGoal(self, goal):
        return (distance(self, goal) <= 10)


    def update(self, eField, goal):
        """Updates the particle's position, velocity, and force based on the
        given ElectricField eField"""
        currentForce = eField.getForceOnParticle(self)
        prevX = self.x
        prevY = self.y
        self.x = self.getX() + ((1.0 * self.vx)/SEC_PER_UPDATE)
        self.y = self.getY() + ((1.0 * self.vy)/SEC_PER_UPDATE)
        self.vx = self.getXVelocity() + (((1.0 * currentForce.getXComponent())/self.getMass()) * SEC_PER_UPDATE)
        self.vy = self.getYVelocity() + (((1.0 * currentForce.getYComponent())/self.getMass()) * SEC_PER_UPDATE)
        self.circle.move(self.x - prevX, self.y - prevY)
        return self.hitGoal(goal)


class Goal:
    def __init__(self, pointPos):
        self.x = pointPos.getX()
        self.y = pointPos.getY()
        self.circle = None
    def getX(self):
        return self.x
    def getY(self):
        return self.y
    def getPosition(self):
        return Point(self.x, self.y)
    def draw(self, window):
        self.circle = Circle(Point(self.x, self.y), 10)
        self.circle.setFill('yellow')
        self.circle.draw(window)

class GameField:
    """Responsible for modelling the field of play"""

    def __init__(self, win, particlePos, goalPos):
        """Creates a GameField object from a graphics window win and an
        initial position of the Particle object at particlePos"""
        self.window = win
        self.height = win.getHeight()
        self.width = win.getWidth()
        self.charges = []
        self.particle = Particle(particlePos)
        self.eField = ElectricField(self)
        self.goal = Goal(goalPos)

    def placeCharge(self, charge, pointPos):
        charge.setPosition(pointPos)
        if charge.circle is None:
            charge.draw(self.window)
        else:
            charge.undraw()
            charge.draw(self.window)


    def addCharge(self, charge):
        """Adds a Charge object charge to the GameField's list of Charge objects"""
        posNeg(charge.getX(), charge.getY(), charge.getCharge(), self.window)
        self.charges.append(charge)

    def draw(self):
        self.particle.draw(self.window)
        self.goal.draw(self.window)

    def update(self):
        """Updates all of the elements contained by the GameField"""
        return self.particle.update(self.eField, self.goal)


class ElectricField:
    """Responsible for modelling the electric field spanning the GameField"""

    def __init__(self, gField):
        """Creates an ElectricField object from an associated GameField gField"""
        self.gameField = gField

    def getForceOnParticle(self, particle):
        """Returns a ForceVector representing the cumulative electric force in the
        ElectricField on a given Particle particle"""
        return getMultipleForceVectors(particle, self.gameField.charges)
    
    def getForceAtPoint(self, point):
        """Returns a ForceVector representing the cumulative electric force in the
        ElectricField at a given Point point"""
        return getMultipleForceVectors(Charge(point,1), self.gameField.charges)